package eval.engine.cplex.InitialCplexCode;

import ilog.opl.IloOplDataHandler;


/**
 * Utility methods for the IloOplDataHandler interface
 * 
 * @author Nicola Calcavecchia
 * 
 *         calcavecchia@elet.polimi.it
 * */

public class OplUtilities {

	private static final String CPLEX_FILE_EQUAL = " = ";
	private static final String CPLEX_FILE_SUFFIX = ";";
	private static final String CPLEX_FILE_START_ARRAY = "[";
	private static final String CPLEX_FILE_STOP_ARRAY = "]";
	private static final String CPLEX_FILE_ARRAY_SEPARATOR = ", ";
	private static final String CPLEX_FILE_MATRIX_SEPARATOR = " ";
	private static final String CPLEX_FILE_ELEMENT_END = "\n";
	private static final String CPLEX_FILE_MATRIX_ARRAY_SEPARATOR = "\n";

	/**
	 * @param dataSource
	 * @param elementName
	 * @param intValue
	 * @param sb
	 * @param useCplexJNI
	 */
	public static void addIntValue(CplexDataSource dataSource, String elementName, int intValue, StringBuffer sb, boolean useCplexJNI) {

		if (useCplexJNI) {
			IloOplDataHandler handler = dataSource.getDataHandler(); 
			handler.startElement(elementName);
			handler.addIntItem(intValue);
			handler.endElement();
		}
		
		if (sb != null) {
			sb.append(  elementName + CPLEX_FILE_EQUAL +  intValue +  CPLEX_FILE_SUFFIX + CPLEX_FILE_ELEMENT_END);
		} 
	}

	/**
	 * @param dataSource
	 * @param elementName
	 * @param doubleValue
	 * @param sb
	 * @param useCplexJNI
	 */
	public static void addNumValue(CplexDataSource dataSource, String elementName, double doubleValue, StringBuffer sb, boolean useCplexJNI) {

		if (useCplexJNI) {
			IloOplDataHandler handler = dataSource.getDataHandler(); 
			handler.startElement(elementName);
			handler.addNumItem(doubleValue);
			handler.endElement();
		}
			
		if (sb != null) {
			sb.append(  elementName + CPLEX_FILE_EQUAL +  doubleValue +  CPLEX_FILE_SUFFIX + CPLEX_FILE_ELEMENT_END);
		}
	}

	
	/**
	 * @param dataSource
	 * @param elementName
	 * @param array
	 * @param sb
	 * @param useCplexJNI
	 */
	public static void addIntArrayValue(CplexDataSource dataSource, String elementName, int[] array, StringBuffer sb, boolean useCplexJNI) {

		if (useCplexJNI) {
			IloOplDataHandler handler = dataSource.getDataHandler(); 

			handler.startElement(elementName);
			handler.startArray();

			for (int value : array) {
				handler.addIntItem(value);
			}

			handler.endArray();
			handler.endElement();
		}
		
		if (sb != null) {
			sb.append(  elementName + CPLEX_FILE_EQUAL + CPLEX_FILE_START_ARRAY );
			if (array.length > 0)
				sb.append(  array[0]);
			for (int index=1; index<array.length; index++) {
				sb.append(  CPLEX_FILE_ARRAY_SEPARATOR +  array[index] );				
			}
			sb.append(  CPLEX_FILE_STOP_ARRAY );
			sb.append(  CPLEX_FILE_SUFFIX);
			sb.append(  CPLEX_FILE_ELEMENT_END);
		}
	}

	/**
	 * @param dataSource
	 * @param elementName
	 * @param array
	 * @param sb
	 * @param useCplexJNI
	 */
	public static <T> void addArrayValue(CplexDataSource dataSource, String elementName, T[] array, StringBuffer sb, boolean useCplexJNI) {

		if (useCplexJNI) {
			IloOplDataHandler handler = dataSource.getDataHandler(); 

			handler.startElement(elementName);
			handler.startArray();

			for (T value : array) {
				if (value instanceof Long) {
					handler.addNumItem((Long)value);
				} else if (value instanceof Double) {
					handler.addNumItem((Double)value);
				} else if (value instanceof Integer) {
					handler.addIntItem((Integer)value);
				} else {
					throw new RuntimeException("Unexpected type for " + value);
				}
			}

			handler.endArray();
			handler.endElement();
		}
		
		if (sb != null) {
			sb.append(  elementName + CPLEX_FILE_EQUAL + CPLEX_FILE_START_ARRAY );
			if (array.length > 0)
				sb.append(  array[0]);
			for (int index=1; index<array.length; index++) {
				sb.append(  CPLEX_FILE_ARRAY_SEPARATOR +  array[index] );				
			}
			sb.append(  CPLEX_FILE_STOP_ARRAY );
			sb.append(  CPLEX_FILE_SUFFIX);
			sb.append(  CPLEX_FILE_ELEMENT_END);
		}
	}

	
	/**
	 * @param dataSource
	 * @param elementName
	 * @param matrix
	 * @param sb
	 * @param useCplexJNI
	 */
	public static <T> void addMatrixValue(CplexDataSource dataSource, String elementName, T[][] matrix, StringBuffer sb, boolean useCplexJNI) {

		if (useCplexJNI) {
			IloOplDataHandler handler = dataSource.getDataHandler(); 

			handler.startElement(elementName);
			handler.startArray();
			for (int i = 0; i < matrix.length; i++) {

				handler.startArray();
				for (int j = 0; j < matrix[i].length; j++) {
					Object value = matrix[i][j];
					if (value instanceof Integer) {
						handler.addIntItem((Integer)value);
					} else if (value instanceof Double) {
						handler.addNumItem((Double)value);
					} else {
						throw new RuntimeException("Unexpected type for " + value);
					}
				}
				handler.endArray();
			}
			handler.endArray();
			handler.endElement();
		}
		
		if (sb != null) {
			String matrixArraySeparator;
			if (matrix.length>0 && matrix[0].length > 0) {
				matrixArraySeparator = CPLEX_FILE_MATRIX_ARRAY_SEPARATOR;
			} else {
				matrixArraySeparator = "";
			}
			sb.append(  elementName + CPLEX_FILE_EQUAL + CPLEX_FILE_START_ARRAY );
			for (int index1=0; index1<matrix.length; index1++) {
				sb.append(matrixArraySeparator + CPLEX_FILE_START_ARRAY );
				for (int index2=0; index2<matrix[index1].length; index2++) {
					sb.append(  CPLEX_FILE_MATRIX_SEPARATOR +  matrix[index1][index2] );
				}
				sb.append(CPLEX_FILE_STOP_ARRAY );
			}
			sb.append(  CPLEX_FILE_STOP_ARRAY );
			sb.append(  CPLEX_FILE_SUFFIX);
			sb.append(  CPLEX_FILE_ELEMENT_END);
		}
	}

	
	/**
	 * @param dataSource
	 * @param elementName
	 * @param matrix
	 * @param sb
	 * @param useCplexJNI
	 */
	public static void addIntMatrixValue(CplexDataSource dataSource, String elementName, int[][] matrix, StringBuffer sb, boolean useCplexJNI) {

		if (useCplexJNI) {
			IloOplDataHandler handler = dataSource.getDataHandler(); 

			handler.startElement(elementName);
			handler.startArray();
			for (int i = 0; i < matrix.length; i++) {

				handler.startArray();
				for (int j = 0; j < matrix[i].length; j++) {
					handler.addIntItem(matrix[i][j]);
				}
				handler.endArray();
			}
			handler.endArray();
			handler.endElement();
		}
		
		if (sb != null) {
			String matrixArraySeparator;
			if (matrix[0].length > 0) {
				matrixArraySeparator = CPLEX_FILE_MATRIX_ARRAY_SEPARATOR;
			} else {
				matrixArraySeparator = "";
			}

			sb.append(  elementName + CPLEX_FILE_EQUAL + CPLEX_FILE_START_ARRAY );
			for (int index1=0; index1<matrix.length; index1++) {
				sb.append(matrixArraySeparator + CPLEX_FILE_START_ARRAY );
				for (int index2=0; index2<matrix[index1].length; index2++) {
					sb.append(  CPLEX_FILE_MATRIX_SEPARATOR +  matrix[index1][index2] );
				}
				sb.append(CPLEX_FILE_STOP_ARRAY );
			}
			sb.append(  CPLEX_FILE_STOP_ARRAY );
			sb.append(  CPLEX_FILE_SUFFIX);
			sb.append(  CPLEX_FILE_ELEMENT_END);
		}
	}

}
